
#ifndef __SPI_H__
#define __SPI_H__

#include "gpio.h"
#include <stdint.h>

#define SPI_PORT_LIST(M) \
    M(SPI_PORT0) \
    M(SPI_PORT1) \
    M(SPI_PORT2)

#define SPI_PORT_ENUM(e) e,

typedef enum {
    SPI_PORT_LIST(SPI_PORT_ENUM)
    SPI_PORT_MAX
} spi_port_e;

typedef enum {
    SPI_DIR_2LINES_FULL_DUPLEX,
    SPI_DIR_2LINES_RX_ONLY,
    SPI_DIR_1LINE_RX,
    SPI_DIR_1LINE_TX
} spi_dir_e;

typedef enum {
    SPI_MODE_MASTER,
    SPI_MODE_SLAVE
} spi_mode_e;

typedef enum {
    SPI_CPOL_LOW,
    SPI_CPOL_HIGH
} spi_cpol_e;

typedef enum {
    SPI_CPHA_1EDGE,
    SPI_CPHA_2EDGE
} spi_cpha_e;

typedef enum {
    SPI_FREQ_36M,
    SPI_FREQ_18M,
    SPI_FREQ_9M,
    SPI_FREQ_4M5,
    SPI_FREQ_2M25,
    SPI_FREQ_1M125,
    SPI_FREQ_562K5,
    SPI_FREQ_281K25,
    SPI_FREQ_140K625
} spi_freq_e;

typedef enum {
    SPI_1ST_BIT_MSB,
    SPI_1ST_BIT_LSB
} spi_1st_bit_e;

typedef struct {
    spi_dir_e dir;
    spi_mode_e mode;
    spi_cpol_e cpol;
    spi_cpha_e cpha;
    spi_freq_e freq;
    spi_1st_bit_e first_bit;
} spi_cfg_t;

#define SPI_BUS_SLAVE_MAX_NUM 16

typedef struct
{
    spi_port_e port;
    spi_cfg_t cfg;
    gpio_pin_e cs_pin[SPI_BUS_SLAVE_MAX_NUM];
    int(*add_cs_pin)(gpio_pin_e pin);
	int(*open)(spi_cfg_t *);
    void(*take)(gpio_pin_e pin);
    void(*release)(gpio_pin_e pin);
	void(*write_read)(uint8_t *, uint8_t *, int);
	void(*close)(void);
	void(*deinit)(void);
} spi_t;

extern spi_t *spi_init(spi_port_e port);
extern spi_t *spi_find_by_port(spi_port_e port);

#endif
